﻿using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interactivity;
using nRoute.ViewModels;
using System.Windows.Data;
using System.ComponentModel;
using nRoute.Behaviors.Interactivity;
using nRoute.Services;
using nRoute.ApplicationServices;
using nRoute.Components.Mapping;
using System.Diagnostics;

namespace nRoute.Behaviors
{
    public class BridgeViewModelBehavior
		 : BindableBehavior<FrameworkElement>
    {

#region Declarations

        private const string VIEW_NOT_RESOLVABLE = "Cannot resolve ViewModel for View of type {0}.";
        private const string APPSERVICE_NOT_INITIALIZED = "nRouteApplicationService has not been initialized.";

        //public static readonly DependencyProperty InitializedCommandProperty =
        //    DependencyProperty.Register("InitializedCommand", typeof(ICommand), typeof(BridgeViewModelBehavior),
        //    new PropertyMetadata(null));

        //public static readonly DependencyProperty InitializedCommandParameterProperty =
        //    DependencyProperty.Register("InitializedCommandParameter", typeof(object), typeof(BridgeViewModelBehavior),
        //    new PropertyMetadata(null));

        public static readonly DependencyProperty LoadedCommandProperty =
            DependencyProperty.Register("LoadedCommand", typeof(ICommand), typeof(BridgeViewModelBehavior),
            new PropertyMetadata(null));

        public static readonly DependencyProperty LoadedCommandParameterProperty =
            DependencyProperty.Register("LoadedCommandParameter", typeof(object), typeof(BridgeViewModelBehavior),
            new PropertyMetadata(null));

#if (!SILVERLIGHT)

        public static readonly DependencyProperty UnloadedCommandProperty =
            DependencyProperty.Register("UnloadedCommand", typeof(ICommand), typeof(BridgeViewModelBehavior),
            new PropertyMetadata(null));

        public static readonly DependencyProperty UnloadedCommandParameterProperty =
            DependencyProperty.Register("UnloadedCommandParameter", typeof(object), typeof(BridgeViewModelBehavior),
            new PropertyMetadata(null));

        private bool _isLoaded;

#endif

#endregion

#region Properties

//        [Category("Common Properties")]
//        public ICommand InitializedCommand
//        {
//            get { return (ICommand)GetValue(InitializedCommandProperty); }
//            set { SetValue( InitializedCommandProperty, value); }
//        }

//        [Category("Common Properties")]
//#if SILVERLIGHT
//        [TypeConverter(typeof(nRoute.Components.TypeConverters.ConvertFromStringConverter))]
//#endif
//        public object InitializedCommandParameter
//        {
//            get { return GetValue(InitializedCommandParameterProperty); }
//            set { SetValue(InitializedCommandParameterProperty, value); }
//        }

        [Category("Common Properties")]
        public ICommand LoadedCommand
        {
            get { return (ICommand)GetValue(LoadedCommandProperty); }
            set { SetValue(LoadedCommandProperty, value); }
        }

        [Category("Common Properties")]
#if SILVERLIGHT
        [TypeConverter(typeof(nRoute.Components.TypeConverters.ConvertFromStringConverter))]
#endif
        public object LoadedCommandParameter
        {
            get { return GetValue(LoadedCommandParameterProperty); }
            set { SetValue(LoadedCommandParameterProperty, value); }
        }

#if (!SILVERLIGHT)

        // Unload Related

        [Category("Common Properties")]
        public ICommand UnloadedCommand
        {
            get { return (ICommand)GetValue(UnloadedCommandProperty); }
            set { SetValue(UnloadedCommandProperty, value); }
        }

        [Category("Common Properties")]
#if SILVERLIGHT
        [TypeConverter(typeof(nRoute.Components.TypeConverters.ConvertFromStringConverter))]
#endif
        public object UnloadedCommandParameter
        {
            get { return GetValue(UnloadedCommandParameterProperty); }
            set { SetValue(UnloadedCommandParameterProperty, value); }
        }

#endif

#if SILVERLIGHT

        //[Category("Common Properties")]
        //public Binding InitializedCommandBinding
        //{
        //    get { return GetBinding(InitializedCommandProperty); }
        //    set { SetBinding<ICommand>(InitializedCommandProperty, value); }
        //}

        //[Category("Common Properties")]
        //public Binding InitializedCommandParameterBinding
        //{
        //    get { return GetBinding(InitializedCommandParameterProperty); }
        //    set { SetBinding<object>(InitializedCommandParameterProperty, value); }
        //}

        [Category("Common Properties")]
        public Binding LoadedCommandBinding
        {
            get { return GetBinding(LoadedCommandProperty); }
            set { SetBinding<ICommand>(LoadedCommandProperty, value); }
        }

        [Category("Common Properties")]
        public Binding LoadedCommandParameterBinding
        {
            get { return GetBinding(LoadedCommandParameterProperty); }
            set { SetBinding<object>(LoadedCommandParameterProperty, value); }
        }

        //[Category("Common Properties")]
        //public Binding UnloadedCommandBinding
        //{
        //    get { return GetBinding(UnloadedCommandProperty); }
        //    set { SetBinding<ICommand>(UnloadedCommandProperty, value); }
        //}

        //[Category("Common Properties")]
        //public Binding UnloadedCommandParameterBinding
        //{
        //    get { return GetBinding(UnloadedCommandParameterProperty); }
        //    set { SetBinding<object>(UnloadedCommandParameterProperty, value); }
        //}

#endif

#endregion

#region Overrides

        protected override void OnAttached()
        {
            base.OnAttached();
            var _type = AssociatedObject.GetType();

            // we check if we can
            if (!nRouteApplicationService.IsInitialized)
                throw new InvalidOperationException(APPSERVICE_NOT_INITIALIZED);

            // we get and inject that into the data context
            var _viewModelMapping = ServiceLocator.GetService(typeof(IViewModelProvider), _type.FullName) as IViewModelProvider;
            if (_viewModelMapping == null) throw new InvalidOperationException(
                string.Format(VIEW_NOT_RESOLVABLE, _type.FullName));

            // we set the view mode
            AssociatedObject.DataContext = _viewModelMapping.CreateViewModelInstance();
            
#if (SILVERLIGHT)

            //// we execute the initialized command
            //if (this.InitializedCommand != null && this.InitializedCommand.CanExecute(null))
            //    this.InitializedCommand.Execute(null);

            AssociatedObject.Loaded += new RoutedEventHandler(AssociatedObject_Loaded);
#else
            AssociatedObject.Unloaded += new RoutedEventHandler(AssociatedObject_Unloaded);
#endif
        }

        protected override void OnDetaching()
        {           
            base.OnDetaching();
        }

#endregion

#region Handlers

#if (SILVERLIGHT)
        
        private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
        {
            if (this.LoadedCommand != null && this.LoadedCommand.CanExecute(null))
            {
                this.LoadedCommand.Execute(null);
            }
            AssociatedObject.Loaded -= new RoutedEventHandler(AssociatedObject_Loaded);
        }

#else

        private void AssociatedObject_Unloaded(object sender, RoutedEventArgs e)
        {
            if (this.UnloadedCommand != null && this.UnloadedCommand.CanExecute(this.UnloadedCommandParameter))
            {
                this.UnloadedCommand.Execute(this.UnloadedCommandParameter);
            }
            AssociatedObject.Unloaded -= new RoutedEventHandler(AssociatedObject_Unloaded);
        }

        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            base.OnPropertyChanged(e);
            if (_isLoaded || this.AssociatedObject == null) return;

            // we use the property changed thing because the bindings to the attached behaviors are not resolved until after
            // the events (loaded/initialized) have passed.. and this is also the reason we have removed initialized command thing

            if (e.Property == LoadedCommandProperty && this.LoadedCommand != null)
            {
                if (this.LoadedCommandParameter != null || !DependencyPropertyHelper.GetValueSource(this, LoadedCommandParameterProperty).IsExpression)
                {
                    _isLoaded = true;
                    if (this.LoadedCommand.CanExecute(this.LoadedCommandParameter))
                        this.LoadedCommand.Execute(this.LoadedCommandParameter);
                }
            }
            else if (e.Property == LoadedCommandParameterProperty && this.LoadedCommandParameter != null)
            {
                if (this.LoadedCommand != null)
                {
                    _isLoaded = true;
                    if (this.LoadedCommand.CanExecute(this.LoadedCommandParameter))
                        this.LoadedCommand.Execute(this.LoadedCommandParameter);
                }
            }
            else if (this.LoadedCommand == null && !DependencyPropertyHelper.GetValueSource(this, LoadedCommandProperty).IsExpression)
            {
                _isLoaded = true;
            }

            //if (e.Property == InitializedCommandProperty && this.InitializedCommand != null)
            //{
            //    if (this.InitializedCommand != null || !DependencyPropertyHelper.GetValueSource(this, InitializedCommandParameterProperty).IsExpression)
            //    {
            //        if (this.InitializedCommand.CanExecute(this.InitializedCommandParameter))
            //            this.InitializedCommand.Execute(this.InitializedCommandParameter);
            //    }
            //}
            //else if (e.Property == InitializedCommandParameterProperty && this.InitializedCommandParameter != null)
            //{
            //    if (this.InitializedCommand != null)
            //    {
            //        if (this.InitializedCommand.CanExecute(this.InitializedCommandParameter))
            //            this.InitializedCommand.Execute(this.InitializedCommandParameter);
            //    }
            //}
        }

#endif

#endregion

    }
}